package com.nextgen.controllers;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.View;

import com.nextgen.bean.Asin;
import com.nextgen.helper.ServiceUtils;
import com.nextgen.services.AsinService;


/**
 * AsinsController class will expose a series of RESTful endpoints
 */
@Controller
public class AsinController {

	@Autowired
	private AsinService asinService;

	@Autowired
	private View jsonView_i;

	private static final String DATA_FIELD = "data";
	private static final String ERROR_FIELD = "error";

	private static final Logger logger_c = Logger.getLogger(AsinController.class);

	/**
	 * Gets a asin by asin id.
	 *
	 * @param asinId_p
	 *            the asin id_p
	 * @return the asin
	 */
	@RequestMapping(value = "/rest/asins/{asinId}", method = RequestMethod.GET)
	public ModelAndView getAsin(@PathVariable("asinId") String asinId_p) {
		Asin asin = null;

		/* validate asin Id parameter */
		if (isEmpty(asinId_p) || asinId_p.length() < 5) {
			String sMessage = "Error invoking getAsin - Invalid asin Id parameter";
			return createErrorResponse(sMessage);
		}

		try {
			asin = asinService.getAsinById(asinId_p);
		} catch (Exception e) {
			String sMessage = "Error invoking getAsin. [%1$s]";
			return createErrorResponse(String.format(sMessage, e.toString()));
		}

		if(asin==null) {
			String sMessage = "Error - Asin with asinId: " + asinId_p+ " NOT found.";
			return createErrorResponse(sMessage);
		}
		logger_c.debug("Returing Asin: " + asin.toString());
		return new ModelAndView(jsonView_i, DATA_FIELD, asin);
	}


	/**
	 * Gets a asin by asin id.
	 *
	 * @param asinId_p
	 *            the asin id_p
	 * @return the asin
	 */
	@RequestMapping(value = "/rest/asins/{sellerId}/{categories}", method = RequestMethod.GET)
	public ModelAndView getAllAsinsForTheSellerBasedOnCategory(@PathVariable("sellerId") String sellerId_p, @PathVariable("categories") String categories_p) {
		List<Asin> asins = null;
		
		/* validate asin Id parameter */
		if (isEmpty(sellerId_p) || sellerId_p.length() < 4) {
			String sMessage = "Error invoking getAllAsinsForTheSellerBasedOnCategory - Invalid seller Id parameter";
			return createErrorResponse(sMessage);
		}

		try {
			List<String> categories = Arrays.asList(categories_p.split(","));
			asins = asinService.getAllAsinsForTheSellerBasedOnCategory(sellerId_p, categories);
		} catch (Exception e) {
			String sMessage = "Error invoking getAsin. [%1$s]";
			return createErrorResponse(String.format(sMessage, e.toString()));
		}
		Map<String, List<Asin>> data = ServiceUtils.getCategoryBasedJson(asins);

		if(asins==null) {
			String sMessage = "Error - Asin with asinId: " + sellerId_p+ " NOT found.";
			return createErrorResponse(sMessage);
		}
		logger_c.debug("Returing Asin: " + asins.toString());
		return new ModelAndView(jsonView_i, DATA_FIELD, data);
	}

	
	/**
	 * Gets all asins.
	 *
	 * @return the asins
	 */
	@RequestMapping(value = "/rest/asins/", method = RequestMethod.GET)
	public ModelAndView getAsins() {
		List<Asin> asins = null;

		try {
			asins = asinService.getAllAsins();
		} catch (Exception e) {
			String sMessage = "Error getting all asins. [%1$s]";
			return createErrorResponse(String.format(sMessage, e.toString()));
		}

		logger_c.debug("Returing Asins: " + asins.toString());
		return new ModelAndView(jsonView_i, DATA_FIELD, asins);
	}

	/**
	 * Creates a new asin.
	 *
	 * @param asin_p
	 *            the asin_p
	 * @return the model and view
	 */
	@RequestMapping(value = { "/rest/asins/" }, method = { RequestMethod.POST })
	public ModelAndView createAsin(@RequestBody Asin asin_p,
			HttpServletResponse httpResponse_p, WebRequest request_p) {

		Asin createdAsin;
		logger_c.debug("Creating Asin: " + asin_p.toString());

		try {
			createdAsin = asinService.createAsin(asin_p);
		} catch (Exception e) {
			String sMessage = "Error creating new asin. [%1$s]";
			return createErrorResponse(String.format(sMessage, e.toString()));
		}

		/* set HTTP response code */
		httpResponse_p.setStatus(HttpStatus.CREATED.value());

		/* set location of created resource */
		httpResponse_p.setHeader("Location", request_p.getContextPath() + "/rest/asins/" + asin_p.getAsinId());

		/**
		 * Return the view
		 */
		return new ModelAndView(jsonView_i, DATA_FIELD, createdAsin);
	}

	/**
	 * Updates asin with given asin id.
	 *
	 * @param asin_p
	 *            the asin_p
	 * @return the model and view
	 */
	@RequestMapping(value = { "/rest/asins/{asinId}" }, method = { RequestMethod.PUT })
	public ModelAndView updateAsin(@RequestBody Asin asin_p, @PathVariable("asinId") String asinId_p,
								   HttpServletResponse httpResponse_p) {

		logger_c.debug("Updating Asin: " + asin_p.toString());

		/* validate asin Id parameter */
		if (isEmpty(asinId_p) || asinId_p.length() < 5) {
			String sMessage = "Error updating asin - Invalid asin Id parameter";
			return createErrorResponse(sMessage);
		}

		Asin asin = null;

		try {
			asin = asinService.updateAsin(asin_p);
		} catch (Exception e) {
			String sMessage = "Error updating asin. [%1$s]";
			return createErrorResponse(String.format(sMessage, e.toString()));
		}

		httpResponse_p.setStatus(HttpStatus.OK.value());
		return new ModelAndView(jsonView_i, DATA_FIELD, asin);
	}

	/**
	 * Deletes the asin with the given asin id.
	 *
	 * @param asinId_p
	 *            the asin id_p
	 * @return the model and view
	 */
	@RequestMapping(value = "/rest/asins/{asinId}", method = RequestMethod.DELETE)
	public ModelAndView removeAsin(@PathVariable("asinId") String asinId_p,
								   HttpServletResponse httpResponse_p) {

		logger_c.debug("Deleting Asin Id: " + asinId_p.toString());

		/* validate asin Id parameter */
		if (isEmpty(asinId_p) || asinId_p.length() < 5) {
			String sMessage = "Error deleting asin - Invalid asin Id parameter";
			return createErrorResponse(sMessage);
		}

		try {
			asinService.deleteAsin(asinId_p);
		} catch (Exception e) {
			String sMessage = "Error invoking getAsins. [%1$s]";
			return createErrorResponse(String.format(sMessage, e.toString()));
		}

		httpResponse_p.setStatus(HttpStatus.OK.value());
		return new ModelAndView(jsonView_i, DATA_FIELD, null);
	}

	public static boolean isEmpty(String s_p) {
		return (null == s_p) || s_p.trim().length() == 0;
	}

	/**
	 * Create an error REST response.
	 *
	 * @param sMessage
	 *            the s message
	 * @return the model and view
	 */
	private ModelAndView createErrorResponse(String sMessage) {
		return new ModelAndView(jsonView_i, ERROR_FIELD, sMessage);
	}

	/**
	 * Injector methods.
	 *
	 * @param asinService_p
	 *            the new asin service
	 */
	public void setAsinService(AsinService asinService_p) {
		asinService = asinService_p;
	}

	/**
	 * Injector methods.
	 *
	 * @param view
	 *            the new json view
	 */
	public void setJsonView(View view) {
		jsonView_i = view;
	}

}
